#include <InvIndexBPlusStorage.hpp>
#include <BPlusTree.hpp>
#include <BPlusTreeNodeLeafData.hpp>
#include <Util.hpp>
#include <STLVector.hpp>
#include <stdio.h>
#include <FTSSException.hpp>
using namespace MAIL; 
using namespace FTSS;

//INT_64 BPlusTreeLeafData::iObjectNum = 0;
//std::map<INT_64, INT_64> BPlusTreeLeafData::dictIdCopyNum;
void InvIndexBPlusStorage::StoreDocumentEntry(WordId_t iWordId, DocumentEntry * pEntry, const Size_t & iDocEntrySize){
	Offset_t iOffset = 0;
	INT_64 iDF = 0;
	// Number of document entires
	DocumentEntry * pTMPEntry = pEntry;
	while (iOffset < iDocEntrySize){
		 iOffset += pTMPEntry -> size;
		 pTMPEntry = (DocumentEntry * )((CHAR_8 *)pTMPEntry + pTMPEntry -> size);
		 // Document frequency
		 ++iDF;
	}

	const BPlusTreeNodeData search_info(iWordId, 0 , iDF);
	// найти пару <iWordHash,0>
	// если пара отсутствует - добавить в дерево ее
	// если пара присутствует - проверить можно ли дописать в LeafData pEntry
	// если можно - дописываем и складываем ее в дерево (дерево перезапишет)
	// если нельзя i- дописываем сколько возможно, создаем новую пару дописываем в нее остаток и increment size пары <iWordHash,0>
	INT_64 current_max_size = pBTree->contains(search_info);
	if (current_max_size != -1){
		// присутствует получаем лист для пары <iWordHash, current_max_chunk>
		BPlusTreeNodeData last_chunk_number_node(search_info.iWordHash, current_max_size);
		STLW::vector<BPlusTreeLeafData*> *leaf_last_chunk_number = 
					pBTree->search(last_chunk_number_node, last_chunk_number_node);
		// проверяем свободное место в листе
		if (leaf_last_chunk_number->empty()){
			fprintf(stderr, "something wrong with Inv Index B Plus Storage, can't found node\n, word_hash=%lu max_size=%ld, contains(1) =%ld, contains(7)=%ld, contains(6)=%ld, sizeofvector=%ld",
				iWordId,
				current_max_size, pBTree->contains(search_info),
				pBTree->contains(last_chunk_number_node), 
				pBTree->contains(BPlusTreeNodeData(iWordId, current_max_size -1)), 
				pBTree->search(search_info, 
				last_chunk_number_node)->size());

			throw LogicException("something wrong with Inv Index B Plus Storage, can't found node");
		}
		BPlusTreeLeafData *leaf_last = (*leaf_last_chunk_number)[0];
		if (leaf_last->getFreeSize() > pEntry->size){
			// можно дописать в конец
			leaf_last->append((CHAR_P)pEntry, pEntry->size);
			// вставить снова
			pBTree->Insert(last_chunk_number_node, *leaf_last);
		} else {
			// нельзя дописать в конец
			// нужно создать новую node, leaf и сделать increment size у search_info
			//fprintf(stderr, "I will create new leaf because can't write whole doc entry in this\n");
			INT_32 part_to_write = leaf_last->getFreeSize();
			leaf_last->append((CHAR_P)pEntry, part_to_write);
			pBTree->Insert(last_chunk_number_node, *leaf_last);
			CHAR_P from = (CHAR_P)pEntry + part_to_write;
			BPlusTreeLeafData oNewLeaf((pEntry->size - part_to_write), from);
			BPlusTreeNodeData oNewNode(last_chunk_number_node.iWordHash, current_max_size + 1, iDF);
			pBTree->Insert(oNewNode, oNewLeaf);
			pBTree->search_and_increment_and_add_DF(BPlusTreeNodeData(iWordId, 0, iDF));
		}
		delete leaf_last_chunk_number;
	}else{
		// отсутствует, добавляем в дерево
//		BPlusTreeLeafData *oLeaf = new BPlusTreeLeafData(pEntry->size, (CHAR_P)pEntry);
		pBTree->Insert(search_info, BPlusTreeLeafData(pEntry->size, (CHAR_P)pEntry));
	}
}


void InvIndexBPlusStorage::StoreDocNum(const Size_t & iIDocNum){
	iDocNum = iIDocNum;
}


FTSS::Pair<DocumentEntryIterator, DocumentEntryIterator> InvIndexBPlusStorage::GetDocumentEntry(const WordId_t & iWordId){
//	fprintf(stderr, "GetDocumentEntry\n");
	BPlusTreeNodeData search_zero(iWordId);
	// получить размер и передать его паре вместе с массивом leafs
	INT_64 size_max_ch = pBTree->contains(search_zero);
	if (size_max_ch != -1){
		// в дереве есть слово с таким хэшем ищем
		BPlusTreeNodeData search_end(iWordId, (INT_32)size_max_ch);
		INT_32 size = (INT_32)(size_max_ch >> 32);
		CHAR_P data_s = pBTree->search_array(search_zero, search_end, (INT_32)size_max_ch + 1, size);
		 FTSS::Pair<DocumentEntryIterator, DocumentEntryIterator> p(
			DocumentEntryIterator((DocumentEntry *)(data_s), 0),
			 DocumentEntryIterator((DocumentEntry *)(data_s), size)
		);
		return p;
/*		DocumentEntryIterator it = p.first;
		DocumentEntryIterator it_end = p.second;
		fprintf(stderr, "size = %d, (INT_32)size_max_ch + 1=%d\n", size, (INT_32)size_max_ch + 1);

		while(it != it_end){
			fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!goto next doc %d\n", (it())->size);
			if (it()->size == 0) throw LogicException("size of docenty = 0");
			++it;
		}
		return p;*/
	}else{
		// если в дереве нет слова с таким хэшем вернуть пару пустых итераторов
		//pBTree->DFSPrintTree();
		//fprintf(stderr, "not word in tree!!11111!!!!!!!!!!!!!1i with hash = %llu\n ", iWordId);
		return FTSS::Pair<DocumentEntryIterator, DocumentEntryIterator>(
				DocumentEntryIterator(NULL, 0),
				DocumentEntryIterator(NULL, 0)
		);
	}
}

// дописать 
Size_t InvIndexBPlusStorage::GetDF(const WordId_t & iWordId){
	
	return 0;
}

Size_t InvIndexBPlusStorage::GetDocNum(){
	return iDocNum;
}

// пока оставить так
INT_32 InvIndexBPlusStorage::IsDeleted(const Size_t & iDocNum){
	return 0;
}

void InvIndexBPlusStorage::StoreZones(const Zone * aIZones, const INT_32 & iIZonesCount){
	   if (aZones != NULL) {delete [] aZones;} 
	            iZonesCount = iIZonesCount;
	            aZones = new Zone[iZonesCount];
	   for (Size_t iI = 0; iI < iZonesCount; ++iI) { aZones[iI] = aIZones[iI]; }
}

Zone * InvIndexBPlusStorage::GetZones(INT_32 & iIZonesCount){
	iIZonesCount = 0; //= iZonesCount;
	return aZones;
}


